package com.hk.core.autoconfigure.exception.reactive;

import com.hk.commons.Status;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.http.HttpStatus;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;

import java.util.HashMap;
import java.util.Map;

import static org.springframework.http.HttpStatus.*;

/**
 * JsonResult 返回的属性值
 *
 * @author Kevin
 * @see org.springframework.boot.web.reactive.error.DefaultErrorAttributes
 */
public class JsonResultErrorAttributes implements ErrorAttributes {

    private static final String ERROR_ATTRIBUTE = STR."\{JsonResultErrorAttributes.class.getName()}.ERROR";

    private Map<String, Object> getInternalErrorAttributes(Throwable error) {
        var result = new HashMap<String, Object>();
        if (null == error) {
            int statusCode = Status.SERVER_ERROR.getStatusCode();
            result.put("statusCode", statusCode);
            result.put("status", HttpStatus.OK.value());
            result.put("message", Status.SERVER_ERROR.getMessage());
        } else {
            jsonResultErrorAttributes(error, result);
        }
        return result;
    }

    private void jsonResultErrorAttributes(Throwable throwable, Map<String, Object> attributes) {
        int statusCode = Status.SERVER_ERROR.getStatusCode(), status = HttpStatus.OK.value();
        var message = Status.SERVER_ERROR.getMessage();
        if (throwable instanceof ResponseStatusException e) {
            if (e.getStatusCode() == METHOD_NOT_ALLOWED) {
                statusCode = Status.METHOD_NOT_ALLOWED.getStatusCode();
                message = Status.METHOD_NOT_ALLOWED.getMessage();
            } else if (e.getStatusCode() == NOT_FOUND) {
                statusCode = Status.NOT_FOUND.getStatusCode();
                message = Status.NOT_FOUND.getMessage();
            } else if (e.getStatusCode() == BAD_REQUEST) {
                statusCode = Status.BAD_REQUEST.getStatusCode();
                message = Status.BAD_REQUEST.getMessage();
            } else if (e.getStatusCode() == UNAUTHORIZED) {
                statusCode = Status.UNAUTHORIZED.getStatusCode();
                message = Status.UNAUTHORIZED.getMessage();
            } else if (e.getStatusCode() == MOVED_PERMANENTLY || e.getStatusCode() == FOUND) {
                statusCode = Status.REDIRECT.getStatusCode();
                message = Status.REDIRECT.getMessage();
            }
        }
        attributes.put("statusCode", statusCode);
        attributes.put("status", status);
        attributes.put("message", message);
    }

    @Override
    public Map<String, Object> getErrorAttributes(ServerRequest request, ErrorAttributeOptions options) {
        return getInternalErrorAttributes(getError(request));
    }

    @Override
    public Throwable getError(ServerRequest request) {
        return (Throwable) request.attribute(ERROR_ATTRIBUTE).orElse(null);
    }

    @Override
    public void storeErrorInformation(Throwable error, ServerWebExchange exchange) {
        exchange.getAttributes().putIfAbsent(ERROR_ATTRIBUTE, error);
    }
}
